// 控制流练习

const util = @import("util.zig");

pub fn run() void {
    // 三元运算符
    var res: i32 = if (true) 123 else 456;
    // 解构可选类型
    const c: ?u32 = null;
    if (c) |val| { // 捕获指针（*val）可用于修改
        res = val; // 捕获的val只读
        util.debugln("value: {}", .{res});
    } else { // else 非必要
        util.debugln("value is null.", .{});
    }

    // 解构错误联合类型
    const val: anyerror!i32 = 0;
    if (val) |v| {
        util.debugln("v: {}", .{v});
    } else |err| {
        util.debugln("err: {any}", .{err});
        unreachable;
    }

    exam_for();
}

// 返回类型名称的字符长度

fn exam_for() void {
    const arr = [_]?i32{ 1, 2, 3, null };
    var sum: i32 = 0;

    // inline 会将 for 循环展开，这允许代码执行一些仅在编译时有效的操作。
    // 需要注意，内联 for 循环要求迭代的值和捕获的值均是编译期已知的。
    // 但 arr 是运行时数组，其元素和长度可能动态变化。
    // NOTE:for 循环在非内联（inline）模式下捕获参数时，只能捕获单个元素。当需要同时获取 元素值 和 索引 时，必须使用以下两种方式之一：
    // 1.普通 for 循环 + 显式索引范围
    // 2.inline for 循环（编译期展开）
    inline for (arr, 0..) |val, idx| { // 需要显式索引范围，才能获取索引
        // sum += if (val) val else 0;
        sum += val orelse 0; // 更好方案：若 val 为 null，使用 0
        // NOTE:
        // Zig 的类型系统严格区分编译期类型和运行时值。代码中的 T 是类型（type），
        // 但 idx 是运行时变量，导致类型推导依赖于运行时信息，违反了 Zig 的 编译期确定性原则。
        // 所以，需要使用inline强制编译期确定
        const T = switch (idx) { // switch 的分支必须返回相同类型
            0 => f32,
            1 => bool,
            2 => i32,
            3 => @TypeOf(null), // null, //null 不是有效的类型表达式
            // NOTE: 在 Debug 和 ReleaseSafe 模式下，unreachable 会调用 panic ，并显示消息达到 unreachable code。
            // 在 ReleaseFast 和 ReleaseSmall 模式下，编译器假设永远不会执行到 unreachable 来对代码进行优化。
            else => unreachable,
        };
        util.debugln("item type: {s}", .{@typeName(T)});
    }
    util.debugln("sum = {}", .{sum});
}
